00001 /* 00002 * Copyright (c) 2013 Battelle Memorial Institute 00003 * Licensed under modified BSD License. A copy of this license can be found 00004 * in the LICENSE file in the top level directory of this distribution. 00005 */ 00006 #pragma once 00007 #define CONFIGURATION_USE_MPI 00008 #ifndef _configuration_h 00009 #include <mpi.h> 00010 // TODO -- any convention on version numbers? 00011 // TODO -- any coding conventions? 00012 #define _configuration_h 201307 00013 //#include <boost/mpi/communicator.hpp> 00014 #include <string> 00015 #include <vector> 00016 #include <memory> 00017 #include <boost/smart_ptr/shared_ptr.hpp> 00018 #ifdef CONFIGURATION_USE_MPI 00019 #include "gridpack/parallel/communicator.hpp" 00020 #endif 00021 namespace gridpack { 00022 namespace utility { 00023 00024 class Configuration { 00025 /** 00026 * We expect execution of a GridPACK application to be determined in part 00027 * by a single input configuration file (perhaps extracted from a database 00028 * or web service). We assume that a configuration file is a binding of a 00029 * hierarchically structured set of keys to a set of values. The 00030 * Configuration module is used to access values and abstract the structure 00031 * of the configuration file which might be concretely represented in a ways 00032 * including XML or with a custom parser. Different components within 00033 * GridPACK will share a common configuration file and we expect then the 00034 * top-level of the key name space to identify the module that is primarily 00035 * associated with a configuration parameter. This provides extensibility over 00036 * time and insulates modules from each other’s internals. 00037 * 00038 * Keys are represented by std::string with the character 00039 * Configuration::KeySeparator,‘.’ (properly escaped in literals) used as 00040 * a name specifier. So “foo.bar” is a key associated by convention with 00041 * module “bar”. 00042 * 00043 * Values are typed and may be of the following primitive types: bool, int, double 00044 * or std::string. We also allow a value to be a std::vector<double>. 00045 * 00046 * We use the term cursor to a common prefix on a set of names. Access to a value 00047 * may be specified by a complete key or by a cursor and the corresponding suffix 00048 * relative to that cursor. Thus a cursor may represent the prefix “foo” and 00049 * relative to that cursor the string “bar” selects the same values as 00050 * “foo.bar”. Aside from factoring out common information for the client, 00051 * it allows a common configuration substructure do be used by different modules. 00052 * 00053 * 00054 * Sample Usage: 00055 * 00056 * string src = "input.xml"; 00057 * Configuration config; 00058 * config.enable_logging(&std::cout); 00059 * if(config.open(src)) { 00060 * // select a value by path name, with default 00061 * string start = config.get("Configuration.Time.Start", "DefaultStart"); 00062 * cout << "Start " << start << endl; 00063 * 00064 * // select a subtree by path 00065 * Configuration::Cursor * time = config.getCursor("Configuration.Time"); 00066 * 00067 * // select a value without specified default 00068 * double step = -1.0; 00069 * if(time->get("Step", & step)) 00070 * cout << "Step " << step << endl; 00071 * 00072 * std::vector<double> dv ; 00073 * if(config.get("Configuration.Option.DefaultVelocity", &dv)) { 00074 * cout << "DefaultVelocity: "; 00075 * for(double e : dv) 00076 * cout << e << " "; 00077 * cout << endl; 00078 * } 00079 * } 00080 * 00081 * Sample use of iterating over all children (which might have same XML element name) 00082 * 00083 * 00084 * p = c->getCursor("Configuration.DynamicSimulation.Faults"); 00085 * Configuration::ChildCursors children; 00086 * p->children(children); 00087 * int i = 0; 00088 * for(auto & c : children) { 00089 * string s = c->get("Branch", "No Branch"); 00090 * cout << i << " " << s << endl; 00091 * i += 1; 00092 * } 00093 * 00094 */ 00095 00096 class ConfigInternals * pimpl; 00097 #ifdef CONFIGURATION_USE_MPI 00098 bool initialize_internal(MPI_Comm comm); 00099 #endif 00100 public: 00101 typedef std::string KeyType; 00102 static const char KeySep = '.'; // inhereted from boost, could change at some cost 00103 00104 /** 00105 * Simple Constructor 00106 */ 00107 Configuration(void); 00108 00109 /** 00110 * Simple Destructor 00111 */ 00112 ~Configuration(void); 00113 00114 /** 00115 * Access a common instance, shared by all modules in configuration database, 00116 */ 00117 static Configuration * configuration(); 00118 00119 /** 00120 * enable logging for diagnostics and provenence (default is std::cout) 00121 */ 00122 void enableLogging(std::ostream * = NULL); 00123 00124 /** 00125 * read a configuration file. true == success, false == some kind of failure 00126 */ 00127 #ifdef CONFIGURATION_USE_MPI 00128 /** 00129 * Open external configuration file on all ranks on communicator comm 00130 * @param file name of external configuration file 00131 * @param Communicator being used in calculation 00132 * @return false if there is an error reading XML file 00133 */ 00134 bool open(const std::string & file, gridpack::parallel::Communicator comm); // on all ranks... 00135 /** 00136 * Deprecated method that initializes configuration on all processes except 00137 * process 0. Can be used in conjunction with "open" call on process 0. 00138 * @param Communicator being used in calculation 00139 * @return false if there is an error reading XML file 00140 */ 00141 bool initialize(gridpack::parallel::Communicator comm); // deprecated.... 00142 #else 00143 /** 00144 * Open external configuration file 00145 * @param file name of external configuration file 00146 */ 00147 bool open(const std::string & file); // rank 0 only 00148 #endif 00149 00150 /** 00151 * For each supported type, there are two variants. One takes a default value 00152 * that is returned if the key is not present in the configuration file, 00153 * the other takes a pointer to an output location and returns a boolean. When the boolean is true 00154 * the output location is updated with the value 00155 * @param KeyType data key in key-value pair 00156 * @param default_value data value in key-value pair 00157 */ 00158 bool get(KeyType, bool default_value); 00159 bool get(KeyType, bool *); 00160 int get(KeyType, int default_value); 00161 bool get(KeyType, int *); 00162 double get(KeyType, double default_value); 00163 bool get(KeyType, double *); 00164 std::string get(KeyType, const std::string & default_value); 00165 // this wrapper makes a common case look a little cleaner 00166 std::string get(KeyType key, const char * default_value) { return get(key, std::string(default_value)); } 00167 bool get(KeyType, std::string *); 00168 00169 // first implementation only works with 3-vectors (which are also individually labeled X,Y,Z) 00170 std::vector<double> get(KeyType, const std::vector<double> & default_value); 00171 bool get(KeyType, std::vector<double>*); 00172 00173 /** 00174 * This class represents a prefix of a set of key names. 00175 * Conveniently this implementation allows it to be the same class 00176 */ 00177 typedef Configuration Cursor ; 00178 typedef boost::shared_ptr<Cursor> CursorPtr; 00179 00180 /** 00181 * select a prefix, returns NULL of the prefix has no defined keys. 00182 * The XML-based implementation on top of boost property maps might 00183 * have multiple elements with the same name. 00184 * This will simply return a pointer to the first, which might not be sufficient. 00185 * This function will set the cursor so that it matches the XML block pointed 00186 * to by the KeyType variable. For example, if the key type is set to 00187 * "Configuration.Powerflow", then subsequent calls to get will look for 00188 * variables within the block deliminated by 00189 * <Configuration><Powerflow>...</Powerflow></Configuration> 00190 * @param KeyType string representing data block to set cursor 00191 * return cursor pointing to correct data block in configuration file 00192 */ 00193 CursorPtr getCursor(KeyType); 00194 00195 /* 00196 * For the root note, return an empty string 00197 * for a cursor, return the key-path as a string that selects this point in the heirarchy 00198 */ 00199 const std::string & path(); 00200 00201 typedef std::vector< CursorPtr > ChildCursors; 00202 /* return a vector of cursors to child elements immediately below this cursor */ 00203 void children(ChildCursors &); 00204 00205 // a ChildElement is a cursor and the leaf name of the element associated with tha cursor. 00206 struct ChildElement { 00207 CursorPtr cursor; 00208 std::string name; 00209 } ; 00210 typedef std::vector< ChildElement > ChildElements; 00211 /* return a vector of cursors to pairs of cursors and names of children immediately below this cursor */ 00212 void children(ChildElements &); 00213 }; 00214 00215 00216 } // utitilities 00217 } // gridpack 00218 #endif